﻿using System;

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using iTextSharp.text;
using iTextSharp.text.pdf;
using System.IO;
using System.Diagnostics;
using System.Collections;
using System.Data;
//--- el siguiente recurso (para exportar a excel) debe ser agregado al proyecto: Referencias-> agregar referencias -> .NET -> Microsoft.Office.Interop.Excel
//--- si no aparece en la lista, debe instalarse, puede ser descargado del siguiente Link: http://support.microsoft.com/kb/897646
using Excel = Microsoft.Office.Interop.Excel;

namespace Maestro_Proveedores.herramientas
{
    /// <remarks>
    /// Esta clase tiene la responsabilidad de exportar un dataGridView a distintos formatos (Consultar Enum: TipoFormatosExportar)
    /// </remarks>
    public class Exportacion
    {
        private static double temp = 0; //--- Esta variable se tuliza para realizar el convertir los distintos campos del presupuesto a numero

        /// <summary>
        /// Exportar dataGridView a un archivo plano
        /// </summary>
        /// <param name="formato">Formato de salida del archivo plano</param>
        /// <param name="dataGridView">DataGridView que sera exportado</param>
        /// <param name="nombreArchivo">Nombre del archivo plano generado</param>
        /// <param name="mostrarColumnasOcultas">¿Mostrar las columas no visibles de DataGridView?</param>
        /// <returns></returns>
        public static bool exportar(Enums.TipoFormatosExportar formato, DataGridView dataGridView, string nombreArchivo, bool mostrarColumnasOcultas)
        {
            DataGridView dataGridView2 = new DataGridView();
            dataGridView2.DataError += new System.Windows.Forms.DataGridViewDataErrorEventHandler(DataError);
            if (!mostrarColumnasOcultas)
            {
               //--- debo pasar la informacion a un segundo dataGridView
               try
                {
                    //-- paso las columnas al nuevo dataGridView
                    foreach (DataGridViewColumn cl in dataGridView.Columns)
                    {
                        dataGridView2.Columns.Add((DataGridViewColumn)cl.Clone());
                    }                    
                    //-- agrego los datos
                    foreach (DataGridViewRow row in dataGridView.Rows)
                    {
                        DataGridViewRow r2 =(DataGridViewRow)row.Clone();
                        int i = 0;
                        foreach (DataGridViewCell cell in row.Cells)
                        {
                            try
                            {
                            r2.Cells[i].Value = cell.Value;
                            }
                            catch (Exception) 
                            {
                                MessageBox.Show(cell.InheritedStyle.ToString());
                            //    return false;
                            }
                            
                            i++;
                        }
                        dataGridView2.Rows.Add(r2);
                    }
                    //-- quito las columnas ocultas del segundo datagridView
                    foreach (DataGridViewColumn cl in dataGridView.Columns)
                    {
                        if (!cl.Visible)
                        {
                            dataGridView2.Columns.Remove(cl.Name);
                        }
                    }
                }
                catch (Exception ex) { MessageBox.Show(ex.Message); }
            }
            //--si vá a mostrar todas las columnas, entonces copio el primer datagridView
            else 
            {
                dataGridView2 = dataGridView;
            }  
            //-- buscar el archivo
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.FileName = nombreArchivo;
            saveFileDialog.FilterIndex = 2;
            saveFileDialog.RestoreDirectory = true;

            if (saveFileDialog.ShowDialog() != DialogResult.OK)
            {
                return true;                
            }
            saveFileDialog.FileName = saveFileDialog.FileName + "." + formato.ToString().ToLower();
            
            if (formato.Equals(Enums.TipoFormatosExportar.PDF))
            {
                return Exportacion.exportPDF(dataGridView2, saveFileDialog.FileName);
            }
            else if (formato.Equals(Enums.TipoFormatosExportar.XLS))
            {
                return Exportacion.exportXLS(dataGridView2, saveFileDialog.FileName);
            }
            else if (formato.Equals(Enums.TipoFormatosExportar.DOC))
            {
                return Exportacion.exportDOC(dataGridView2, saveFileDialog.FileName);
            }
            else if (formato.Equals(Enums.TipoFormatosExportar.CSV))
            {
                return Exportacion.exportCSV(dataGridView2, saveFileDialog.FileName);
            }
            else if (formato.Equals(Enums.TipoFormatosExportar.HTML))
            {
                return Exportacion.exportHTML(dataGridView2, saveFileDialog.FileName);
            } 
            return false;
        }
        /// <summary>
        /// Exportar DataTable a un archivo plano (SOLO EXPORTA EN FORMATO EXCEL !!!)
        /// </summary>
        /// <param name="dataTable">DataTable que sera exportado</param>
        /// <param name="nombreArchivo">Nombre del archivo plano generado</param>
        /// <returns></returns>
        public static string exportar(DataTable dataTable, string nombreArchivo)
        {

            string rutaArchivo;

            try
            {             
                Cursor.Current = Cursors.WaitCursor;

                //-- buscar el archivo
                SaveFileDialog saveFileDialog = new SaveFileDialog();
                saveFileDialog.FileName = nombreArchivo;
                saveFileDialog.FilterIndex = 2;
                saveFileDialog.RestoreDirectory = true;

                if (saveFileDialog.ShowDialog() != DialogResult.OK)
                {
                    return "Cancelado";
                }                
                saveFileDialog.FileName = saveFileDialog.FileName + ".xls";
            
                //-- genero el excel.
                Excel.Application xlApp;
                Excel.Workbook xlWorkBook;
                Excel.Worksheet xlWorkSheet;
                object misValue = System.Reflection.Missing.Value;

                xlApp = new Excel.Application();
                xlWorkBook = xlApp.Workbooks.Add(true);
                xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);//(Excel.Worksheet)xlWorkBook.ActiveSheet;
                //Se colocan los titulos de las columnas
                for (int i = 0; i < dataTable.Columns.Count; i++)
                {
                    xlWorkSheet.Cells[1, i + 1] = dataTable.Columns[i].ColumnName.ToUpper();
                }
                for (int i = 0; i < dataTable.Rows.Count; i++)
                {
                    Object[] items = dataTable.Rows[i].ItemArray;
                    for (int j = 0; j < items.Length; j++)
                    {
                        xlWorkSheet.Cells[i + 2, j + 1] = items[j].ToString();                        
                    }
                }
                xlWorkSheet.Columns.AutoFit();
                xlWorkBook.SaveAs(saveFileDialog.FileName, Excel.XlFileFormat.xlWorkbookNormal, misValue, misValue, misValue, misValue, Excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue);
                xlWorkBook.Close(true, misValue, misValue);
                xlApp.Quit();
                Exportacion.releaseObject(xlWorkSheet);
                Exportacion.releaseObject(xlWorkBook);
                Exportacion.releaseObject(xlApp);
                rutaArchivo = saveFileDialog.FileName;
            }
            catch (Exception ex)
            {
                Cursor.Current = Cursors.Default;
                Maestro_Proveedores.herramientas.MessageException.show(ex);
                return "error";
            }
            Cursor.Current = Cursors.Default;
            return rutaArchivo;
        }
        
        private static Boolean exportPDF(DataGridView dataGridView, string ruta)
        {            
            try   
            {     
                Document doc = new Document(PageSize.A4.Rotate(), 10, 10,10, 10);
                FileStream file = new FileStream(ruta,FileMode.OpenOrCreate,FileAccess.ReadWrite,FileShare.ReadWrite); 
                PdfWriter.GetInstance(doc, file);     
                doc.Open();     
                Exportacion.generarDocumento(doc,dataGridView);     
                doc.Close();     
                Process.Start(ruta);    
            }  
            catch (Exception ex)    
            {
                Maestro_Proveedores.herramientas.MessageException.show(ex);
                //MessageBox.Show("La operacion no pudo realizarse.\nEl archivo esta abierto ó el disco de destino es de solo lectura.");
                return false;                
            }
            return true;
        }

        private static Boolean exportCSV(DataGridView dataGridView, string ruta)
        {
            try
            {
                //string ruta=Application.StartupPath+"/"+nombreArchivo+".xls";
                FileStream fs = new FileStream(ruta, FileMode.Create, FileAccess.ReadWrite);
                StreamWriter w = new StreamWriter(fs);
                string comillas = char.ConvertFromUtf32(34);
                StringBuilder csv = new StringBuilder();
                
                //--- titulos
                foreach (DataGridViewColumn item in dataGridView.Columns)
                {
                    if(!item.Index.Equals(dataGridView.ColumnCount-1))
                        csv.Append(comillas + item.HeaderText.ToUpper() + comillas + ",");    
                    else
                        csv.Append(comillas + item.HeaderText.ToUpper() + comillas + Environment.NewLine);
                }

                //se pasan los datos del dataGridView a la tabla   
                foreach (DataGridViewRow row in dataGridView.Rows)
                {
                    foreach (DataGridViewCell item in row.Cells)
                    {
                        if (!item.ColumnIndex.Equals(dataGridView.ColumnCount - 1))
                            csv.Append(comillas + item.FormattedValue.ToString() + comillas + ",");
                        else
                            csv.Append(comillas + item.FormattedValue.ToString() + comillas + Environment.NewLine);
                    }
                }

                w.Write(csv.ToString());
                w.Close();
                Process.Start(ruta);
            }
            catch (Exception ex)
            {
                Maestro_Proveedores.herramientas.MessageException.show(ex);
                return false;
            }
            return true;
        }
        
        private static Boolean exportXLS(DataGridView dataGridView2, string ruta)
        {
            try
            {
                Cursor.Current = Cursors.WaitCursor;
                //-- genero el excel.
                Excel.Application xlApp;
                Excel.Workbook xlWorkBook;
                Excel.Worksheet xlWorkSheet;
                object misValue = System.Reflection.Missing.Value;

                xlApp = new Excel.Application();
                xlWorkBook = xlApp.Workbooks.Add(true);
                xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);//(Excel.Worksheet)xlWorkBook.ActiveSheet;
                //Se colocan los titulos de las columnas
                foreach (DataGridViewColumn col in dataGridView2.Columns)
                {
                    xlWorkSheet.Cells[1,col.Index+1] = col.HeaderText.ToUpper();                    
                }
                foreach (DataGridViewRow row in dataGridView2.Rows)
                {
                    foreach (DataGridViewCell item in row.Cells)
                    {
                        //try
                        //{
                            xlWorkSheet.Cells[row.Index + 2, item.ColumnIndex + 1] = item.FormattedValue.ToString();
                        //}
                        //catch (Exception) 
                        //{
                        //    MessageBox.Show(item.InheritedStyle.ToString());
                        //    return false;
                        //}
                    }                    
                }
                xlWorkSheet.Columns.AutoFit();
                xlWorkBook.SaveAs(ruta, Excel.XlFileFormat.xlWorkbookNormal, misValue, misValue, misValue, misValue, Excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue);
                xlWorkBook.Close(true, misValue, misValue);
                xlApp.Quit();
                Exportacion.releaseObject(xlWorkSheet);
                Exportacion.releaseObject(xlWorkBook);
                Exportacion.releaseObject(xlApp);               
            }
            catch (Exception ex)
            {
                Cursor.Current = Cursors.Default;
                Maestro_Proveedores.herramientas.MessageException.show(ex);
                return false;
            }
            Cursor.Current = Cursors.Default;
            return true;
        }

        private static Boolean exportDOC(DataGridView dataGridView, string ruta)
        {
            return Exportacion.generar(dataGridView, ruta);
        }

        private static Boolean exportHTML(DataGridView dataGridView, string ruta)
        {
            return Exportacion.generar(dataGridView, ruta);
        }
                        
        private static void generarDocumento(Document document, DataGridView dataGridView)
        {  
            //se crea un objeto PdfTable con el numero de columnas del  dataGridView  
            PdfPTable datatable = new PdfPTable(dataGridView.ColumnCount);  //asignamos algunas propiedades para el diseño del pdf  
            datatable.DefaultCell.Padding = 3;  
            float[] headerwidths = Exportacion.getTamañoColumnas(dataGridView);  
            datatable.SetWidths(headerwidths);  
            datatable.WidthPercentage = 100;  
            datatable.DefaultCell.BorderWidth = 2;  
            datatable.DefaultCell.HorizontalAlignment = Element.ALIGN_CENTER;  
            //SE GENERA EL ENCABEZADO DE LA TABLA EN EL PDF  
            for (int i = 0; i < dataGridView.ColumnCount; i++)  
            {
                datatable.AddCell(dataGridView.Columns[i].HeaderText.ToUpper());  
            }  
            datatable.HeaderRows = 1;  
            datatable.DefaultCell.BorderWidth = 1;  
            //SE GENERA EL CUERPO DEL PDF  
            for (int i = 0; i < dataGridView.RowCount; i++)  
            {   
                for (int j = 0; j < dataGridView.ColumnCount; j++)    
                {     
                    datatable.AddCell(dataGridView[j, i].FormattedValue.ToString());    
                }  
                datatable.CompleteRow(); 
            } 
            //SE AGREGA LA PDFPTABLE AL DOCUMENTO 
            document.Add(datatable);
        } 
        /// <summary>
        /// Metodo que obtiene los tamaños de las columnas del DataGridView
        /// </summary>
        /// <param name="dg">DataGridView</param>
        /// <returns>tamaño (ancho) de cada una de las columnas del DataGridView en pixeles</returns>
        private static float[] getTamañoColumnas(DataGridView dg)
        {  
            float[] values = new float[dg.ColumnCount];  
            for (int i = 0; i < dg.ColumnCount; i++)      
            {        
                values[i] = (float)dg.Columns[i].Width;      
            }  
            return values;
        }

        private static bool generar(DataGridView dataGridView, string ruta) 
        {
            try
            {
                // string ruta=Application.StartupPath+"/"+nombreArchivo+".xls";
                FileStream fs = new FileStream(ruta, FileMode.Create, FileAccess.ReadWrite);
                StreamWriter w = new StreamWriter(fs);
                string comillas = char.ConvertFromUtf32(34);
                StringBuilder html = new StringBuilder();
                html.Append(@"<html>");
                html.Append(@"<head>");
                html.Append(@"<meta http-equiv=" + comillas + "Content-Type" + comillas + "content=" + comillas + "text/html; charset=utf-8" + comillas + "/>");
                html.Append(@"<title>Untitled Document</title>");
                html.Append(@"</head>");
                html.Append(@"<body>");         //Generando encabezados del archivo         //(aquí podemos dar el formato como a una tabla de HTML)        
                html.Append(@"<table WIDTH=730 CELLSPACING=0 CELLPADDING=10 border=8 BORDERCOLOR=" + comillas + "#333366" + comillas + " bgcolor=" + comillas + "#FFFFFF" + comillas + ">");
                html.Append(@"<tr> <b>");

                foreach (DataGridViewColumn item in dataGridView.Columns)
                {
                    html.Append(@"<th>" + item.HeaderText.ToUpper() + "</th>");
                }
                html.Append(@"</tr>");

                //se pasan los datos del dataGridView a la tabla   
                foreach (DataGridViewRow row in dataGridView.Rows)
                {
                    html.Append(@"<tr>");
                    foreach (DataGridViewCell item in row.Cells)
                    {
                        html.Append(@"<td>" + item.FormattedValue.ToString() + "</td>");
                    }
                    html.Append(@"</tr>");
                }
                html.Append(@"</body>");
                html.Append(@"</html>");
                w.Write(html.ToString());
                w.Close();
            //    Process.Start(ruta);
            }
            catch (Exception ex)
            {
                Maestro_Proveedores.herramientas.MessageException.show(ex);
                return false;
            }
            return true;
        }
        /// <summary>
        /// Este metodo es utilizado para gereral erchivo de excel.
        /// </summary>
        /// <param name="obj"></param>
        private static void releaseObject(object obj)
        {
            try
            {
                System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
                obj = null;
            }
            catch (Exception ex)
            {
                obj = null;
                MessageBox.Show("Exception Occured while releasing object " + ex.ToString());
            }
            finally
            {
                GC.Collect();
            }
        }

        private static void DataError(object sender, DataGridViewDataErrorEventArgs e)
        {

        }

        public static string exportar_NUEVO(DataTable dataTable, bool formatearCabecera)
        {
            if (dataTable.Columns.Count >= 10 && dataTable.Rows.Count > 5000)
            {
                if (MessageBox.Show("La tabla que desea exportar tiene mucha información. Es posible que tarde varios minutos preparando la informacion. \n\n¿Desea Exportarla a un archivo EXCEL sin formato para que el proceso sea mas rapido? \n\nSeleccione NO para exportar con formato.", "Confirmacion", MessageBoxButtons.YesNo) == DialogResult.Yes)
                {
                    return exportarXLS_Sencillo_NUEVO(dataTable);
                }
            }

            string nombreArchivo = dataTable.TableName;
            string rutaArchivo;
            string ColumnasExcluidas = ""; //"[ID],";

            try
            {

                //-- buscar el archivo
                SaveFileDialog saveFileDialog = new SaveFileDialog();
                saveFileDialog.FileName = nombreArchivo;
                saveFileDialog.FilterIndex = 2;
                saveFileDialog.RestoreDirectory = true;

                if (saveFileDialog.ShowDialog() != DialogResult.OK)
                {
                    return "Cancelado";
                }
                Cursor.Current = Cursors.WaitCursor;
                saveFileDialog.FileName = saveFileDialog.FileName + ".xls";

                //-- genero el excel.
                Excel.Application xlApp;
                Excel.Workbook xlWorkBook;
                Excel.Worksheet xlWorkSheet;
                object misValue = System.Reflection.Missing.Value;

                xlApp = new Excel.Application();
                xlWorkBook = xlApp.Workbooks.Add(true);
                xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);//(Excel.Worksheet)xlWorkBook.ActiveSheet;

                //--- Coloco un borde al recuadro de la pagina
                Excel.Range oRange1 = (Excel.Range)xlWorkSheet.get_Range(xlWorkSheet.Cells[1, 1], xlWorkSheet.Cells[dataTable.Rows.Count + 1, dataTable.Columns.Count]);
                oRange1.Borders.LineStyle = Excel.XlLineStyle.xlContinuous;
                //oRange1.Borders.Color = System.Drawing.ColorTranslator.ToWin32(System.Drawing.Color.Black);


                //--- Formateo la cabecera
                if (formatearCabecera)
                {
                    Excel.Range oRange2 = (Excel.Range)xlWorkSheet.get_Range(xlWorkSheet.Cells[1, 1], xlWorkSheet.Cells[1, dataTable.Columns.Count]);
                    oRange2.Font.Bold = true;
                    oRange2.HorizontalAlignment = Excel.XlHAlign.xlHAlignCenter;
                    oRange2.Interior.ColorIndex = 33;  // (36: amarillo, 43: Verde, 39: Morado) ///---- Paleta de colores: http://dmcritchie.mvps.org/excel/colors.htm 
                    object _missing;
                    _missing = System.Reflection.Missing.Value;
                    oRange2.AutoFilter(1, _missing, Excel.XlAutoFilterOperator.xlAnd, _missing, true);
                }

                //Se colocan los titulos de las columnas
                for (int i = 0; i < dataTable.Columns.Count; i++)
                {
                    if (!ColumnasExcluidas.Contains("[" + dataTable.Columns[i].ColumnName.ToUpper() + "]"))
                    {
                        xlWorkSheet.Cells[1, i + 1] = dataTable.Columns[i].ColumnName.ToUpper();
                    }
                    else
                    {
                        xlWorkSheet.Cells[1, i + 1] = "";
                    }
                }

                //--- Se agregan los datos
                //if (dataTable.Rows.Count > 20000 && dataTable.Columns.Count > 10)
                //{
                //    MessageBox.Show("La informacion que desea exportar tiene demasiados registros, NO se ");
                //}

                for (int i = 0; i < dataTable.Rows.Count; i++)
                {
                    Object[] items = dataTable.Rows[i].ItemArray;
                    for (int j = 0; j < dataTable.Columns.Count; j++)
                    {
                        if (!ColumnasExcluidas.Contains("[" + dataTable.Columns[j].ColumnName.ToUpper() + "]"))
                        {
                            xlWorkSheet.Cells[i + 2, j + 1] = (dataTable.Columns[j].DataType.Name.Equals("Decimal") ? getFormatoMoneda(items[j].ToString()) : items[j].ToString());
                        }
                        else
                        {
                            xlWorkSheet.Cells[i + 2, j + 1] = "";
                        }
                    }
                }
                xlWorkSheet.Columns.AutoFit();
                try { xlWorkBook.SaveAs(saveFileDialog.FileName, Excel.XlFileFormat.xlWorkbookNormal, misValue, misValue, misValue, misValue, Excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue); }
                catch (Exception ex) { MessageException.show(ex); return "Cancelado"; }
                xlWorkBook.Close(true, misValue, misValue);
                xlApp.Quit();
                System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWorkSheet);
                System.Runtime.InteropServices.Marshal.ReleaseComObject(xlWorkBook);
                System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);

                xlWorkSheet = null;
                xlWorkBook = null;
                xlApp = null;

                rutaArchivo = saveFileDialog.FileName;
            }
            catch (Exception ex)
            {
                Cursor.Current = Cursors.Default;
                MessageException.show(ex);
                return "Error";
            }
            GC.Collect();
            Cursor.Current = Cursors.Default;
            return rutaArchivo;
        }
        /// <summary>
        /// Cuando la grilla que se desea exportar tiene muchos datos, el usuario tiene la opcion de exportar los datos a un excel sin formato para que dicha exportacion sea mas rapida
        /// </summary>
        /// <param name="dataTable"></param>
        /// <returns></returns>
        public static string exportarXLS_Sencillo_NUEVO(DataTable dataTable)
        {
            string nombreArchivo = dataTable.TableName;
            string rutaArchivo;
            try
            {
                //-- buscar el archivo
                SaveFileDialog saveFileDialog = new SaveFileDialog();
                saveFileDialog.FileName = nombreArchivo;
                saveFileDialog.FilterIndex = 2;
                saveFileDialog.RestoreDirectory = true;

                if (saveFileDialog.ShowDialog() != DialogResult.OK)
                {
                    return "Cancelado";
                }
                Cursor.Current = Cursors.WaitCursor;
                saveFileDialog.FileName = saveFileDialog.FileName + ".xls";
                rutaArchivo = saveFileDialog.FileName;

                const string FIELDSEPARATOR = "\t";
                const string ROWSEPARATOR = "\n";
                StringBuilder output = new StringBuilder();
                // Escribir encabezados    
                foreach (DataColumn dc in dataTable.Columns)
                {
                    output.Append(dc.ColumnName);
                    output.Append(FIELDSEPARATOR);
                }
                output.Append(ROWSEPARATOR);
                foreach (DataRow item in dataTable.Rows)
                {
                    foreach (object value in item.ItemArray)
                    {
                        output.Append(value.ToString().Replace('\n', ' ').Replace('\r', ' ')/*.Replace('.', ',')*/);
                        output.Append(FIELDSEPARATOR);
                    }
                    // Escribir una línea de registro        
                    output.Append(ROWSEPARATOR);
                }
                StreamWriter sw = new StreamWriter(rutaArchivo);
                sw.Write(output.ToString());
                sw.Close();
            }
            catch (Exception ex)
            {
                Cursor.Current = Cursors.Default;
                MessageException.show(ex);
                return "Error";
            }
            return string.Empty;
        }

        public static string getFormatoMoneda(string valor)
        {
            if (!double.TryParse(valor.Trim(), out temp))
            {
                return valor;
            }
            return getFormatoMoneda(temp);
        }
        public static string getFormatoMoneda(double valor)
        {
            return valor.ToString("N", System.Globalization.CultureInfo.CurrentCulture.NumberFormat); //"#,0.00"
        }

    }
}
